package addressBook;

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Vector;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.ui.part.*;
import org.eclipse.swt.events.MenuAdapter;
import org.eclipse.swt.events.MenuEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.SWT;

import addressBook.DataEntryDialog;
import addressBook.Entry;
import addressBook.AdressBookXMLParser;

public class AdressBook extends ViewPart {
	
	private Composite parent;	
	private Table table;
	private boolean isModified;
	
	private static final String[] columnNames = {"Last Name",
												 "First name",
												 "Patronymic Name",
												 "Phone"
												 };
	
	private static Vector<Entry> entries = null;
	
	private static SAXParser parser;
	private static String path = "book.xml";

	public AdressBook() {
		entries = new Vector<Entry>();
		try {
			AdressBookXMLParser sample = new AdressBookXMLParser();         
            SAXParserFactory factory = SAXParserFactory.newInstance();
            parser = factory.newSAXParser();
            parser.parse(path, sample);
        }
        catch (Exception e) {
            e.printStackTrace(System.err);
        }
	}

	public void createPartControl(Composite parent) {
		this.parent = parent;			
		createView();
	}
	
	private void createView() {
		table = new Table(parent, SWT.SINGLE | SWT.BORDER | SWT.FULL_SELECTION);
		table.setLinesVisible(true);
		table.setHeaderVisible(true);
		table.setMenu(createPopUpMenu());
		//table.setBackground(new Color(null,200,200,200));
		table.addSelectionListener(new SelectionAdapter() {
			public void widgetDefaultSelected(SelectionEvent e) {
				TableItem[] items = table.getSelection();
				if (items.length > 0) editEntry(items[0]);
			}
		});
		
		for(int i = 0; i < columnNames.length; i++) {
			TableColumn column = new TableColumn(table, SWT.NONE);
			column.setText(columnNames[i]);
			column.setWidth(150);
			final int columnIndex = i;
			column.addSelectionListener(new SelectionAdapter() {		
				public void widgetSelected(SelectionEvent e) {
					sort(columnIndex);
				}
			});
		}
		
		loadBookInTable();
	}
	
	private void loadBookInTable() {
		String[][] tableInfo = new String[entries.size()][table.getColumnCount()];
		
		Cursor waitCursor = new Cursor(parent.getDisplay(), SWT.CURSOR_WAIT);
		parent.setCursor(waitCursor);
		
		for(int q=0;q<tableInfo.length;q++)
			for(int q1=0;q1<tableInfo[q].length;q1++)
				tableInfo[q][q1]="";
		
		int i=0;
		for (Entry en: entries )
		{
			tableInfo[i][0] = en.getLastName();
			tableInfo[i][1] = en.getName();
			tableInfo[i][2] = en.getPatrName();
			
			String value = en.getFieldValue(columnNames[3]);
			if (value != null) tableInfo[i][3] = value;
			
			i++;
		}
		
		parent.setCursor(null);
		waitCursor.dispose();
		
		for (int j = 0; j < tableInfo.length; j++) {
			TableItem item = new TableItem(table, SWT.NONE);
			item.setText(tableInfo[j]);
		}
		
		isModified = false;
	}
	
	private void displayError(String msg) {
		MessageBox box = new MessageBox(parent.getShell(), SWT.ICON_ERROR);
		box.setMessage(msg);
		box.open();
	}
	
	private void sort(int column) {
		if(table.getItemCount() <= 1)	return;

		TableItem[] items = table.getItems();
		String[][] data = new String[items.length][table.getColumnCount()];
		for(int i = 0; i < items.length; i++) {
			for(int j = 0; j < table.getColumnCount(); j++) {
				data[i][j] = items[i].getText(j);
			}
		}
		
		Arrays.sort(data, new RowComparator(column));
		
		for (int i = 0; i < data.length; i++) {
			items[i].setText(data[i]);
		}
		
	}
	
	public static boolean addEnrty (Entry en){
		if (!entries.contains(en)) {
			entries.add(en);
			return true;
		}
		return false;
	}
	
	private void newEntry() {
		DataEntryDialog dialog = new DataEntryDialog(parent.getShell());
		dialog.setLabels(columnNames);
		String[] data = dialog.open();
		if (data != null) {
			boolean isEmpty = true;
			for (int i = 0; i<data.length;i++) {
				if (data[i] != null) isEmpty = false; 
			}
			if (isEmpty) {
				displayError("Wrong Input");
				return;
			}
			
			for (int i = 0; i<data.length;i++) {
				if (data[i] == null) data [i] = "";
			}
			
			Entry en = new Entry(data[0],data[1],data[2]);
			if (addEnrty (en)) {
				if (!data[3].equals("")) en.addField(columnNames[3],data[3]);
				TableItem item = new TableItem(table, SWT.NONE);
				item.setText(data);
				isModified = true;
			}
			else {
				displayError("Dublicate entry for" + en.getLastName() + " " + en.getName() + " " + en.getPatrName());
			}
		}
	}
	
	private void editEntry(TableItem item) {
		DataEntryDialog dialog = new DataEntryDialog(parent.getShell());
		dialog.setLabels(columnNames);
		String[] data = new String[table.getColumnCount()];
		for (int i = 0; i < data.length; i++) {
			data[i] = item.getText(i);
		}
		dialog.setValues(data);
		
		Entry en = new Entry(data[0], data[1], data[2]);
		if (entries.contains(en)) {
			en = entries.get(entries.indexOf(en));
		}
		else {
			return;
		}
			
		data = dialog.open();
		
		
		if (data != null) {
			boolean isEmpty = true;
			for (int i = 0; i<data.length;i++) {
				if (data[i] != null) isEmpty = false; 
			}
			if (isEmpty) return;
			
			for (int i = 0; i<data.length;i++) {
				if (data[i] == null) data [i] = "";
			}
			
			Entry enMod = new Entry(data[0], data[1], data[2]);
			if ( (!en.equals(enMod)) && (entries.contains(enMod)) ) {
				displayError("Dublicate entry for " + en.getLastName() + " " + en.getName() + " " + en.getPatrName());
				return;
			}
			en.setLastName(data[0]);
			en.setName(data[1]);
			en.setPatrName(data[2]);
			if (en.containsField(columnNames[3]))
				en.modifyField(columnNames[3], data[3]);
			else
				en.addField(columnNames[3], data[3]);
			
			item.setText(data);
			isModified = true;
		}
	}
	
	private boolean deleteEntry(TableItem item) {
		String[] data = new String[table.getColumnCount()];
		for (int i = 0; i < data.length; i++) {
			data[i] = item.getText(i);
		}
		Entry en = new Entry (item.getText(0),item.getText(1),item.getText(2));
		
		if (entries.contains(en)) {
			entries.remove(en);
			isModified = true;
			return true;
		}
		else 
			return false;
	}
	
	private Menu createPopUpMenu() {
		Menu popUpMenu = new Menu(parent.getShell(), SWT.POP_UP);

		popUpMenu.addMenuListener(new MenuAdapter() {
			public void menuShown(MenuEvent e) {
				Menu menu = (Menu)e.widget;
				MenuItem[] items = menu.getItems();
				int count = table.getSelectionCount();
				items[1].setEnabled(count != 0); // Edit
				items[2].setEnabled(count != 0); // Delete
				items[4].setEnabled(isModified); // Save
			}
		});

		//New
		MenuItem item = new MenuItem(popUpMenu, SWT.CASCADE);
		item.setText("New");
		item.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				newEntry();
			}
		});	
		
		//Edit
		item = new MenuItem(popUpMenu, SWT.CASCADE);
		item.setText("Edit");
		item.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				TableItem[] items = table.getSelection();
				if (items.length == 0) return;
				editEntry(items[0]);
			}
		});
		
		//Delete
		item = new MenuItem(popUpMenu, SWT.CASCADE);
		item.setText("Delete");
		item.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				TableItem[] items = table.getSelection();
				if (items.length == 0) return;
				if (deleteEntry(items[0]))
					items[0].dispose();
			}
		});
		
		new MenuItem(popUpMenu, SWT.SEPARATOR);	
		
		//Save
		item = new MenuItem(popUpMenu, SWT.CASCADE);
		item.setText("Save");
		item.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				saveEntriesToFile(path);
			}
		});
		
		/*
		//Find...
		item = new MenuItem(popUpMenu, SWT.NULL);
		item.setText("Find");
		item.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				searchDialog.open();
			}
		});
		*/

		return popUpMenu;
	}
	
	public void saveEntriesToFile(String path)
	{
		Cursor waitCursor = new Cursor(parent.getDisplay(), SWT.CURSOR_WAIT);
		parent.setCursor(waitCursor);
		
		try  {
			PrintWriter out = new PrintWriter(new FileWriter(path));
			
			out.println("<?xml version=\"1.0\"?>");
			out.println("<adressbook>");
			out.println();
			
			if (!entries.isEmpty())
				for (Entry en: entries) {
					out.println("<entry Name=\"" + en.getName()+"\" LastName=\""+en.getLastName()+"\" PatrName=\""+en.getPatrName()+"\" >");
					for (String s: en.getFieldsMap().keySet()) {
						out.println("  <field name=\"" + s + "\" val=\"" + en.getFieldValue(s)+"\" />");
					}
					out.println("</entry>");
					out.println();
				}
			
			out.println("</adressbook>");
			out.close();
		}
		catch (IOException e) {
			System.out.print("Erron \n" + e);
		}
		
		parent.setCursor(null);
		waitCursor.dispose();
		
		isModified = false;
	}
	
	public static Vector<Entry> getEntries() {
		return entries;
	}
	
	public void setFocus() {
		table.setFocus();
	}
	
	public void dispose() {
		saveEntriesToFile(path);
		super.dispose();
	}
	
	private class RowComparator implements Comparator {
		private int column;
		
		public RowComparator(int col) {
			column = col;
		}
		
		public int compare(Object obj1, Object obj2) {
			String[] row1 = (String[])obj1;
			String[] row2 = (String[])obj2;
			
			return row1[column].compareTo(row2[column]);
		}
	}
}